package laxutils

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"go.uber.org/zap"
	"io"
	"io/ioutil"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"
)

//  @Desc: 读取xml文件,解析到target里面
//  @param filePath 文件路径+名字
//  @param target 解析目标变量
//  @return error 返回error
func LoadXmlFile(filePath string, target interface{}) error {
    xmlContent, err := ioutil.ReadFile(filePath)
    if err != nil {
        return err
    }
    if err = xml.Unmarshal(xmlContent, &target); err != nil {
        return err
    }
    return nil
}

// @Desc: 读取json文件,解析到target里面
// @param filePath 文件路径+名字
// @param target 目标变量
// @return error 结果
func LoadJsonFile(filePath string, target interface{}) error {
	jsonContent, err := ioutil.ReadFile(filePath)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(jsonContent, &target); err != nil {
		return err
	}
	return nil
}

//  @Desc: zlib解压
//  @param buf 原字符串
//  @return []byte 解压后的字符串
func ZlibDecompress(buf []byte) []byte {
    b := bytes.NewReader(buf)
    var out bytes.Buffer
    r, _ := zlib.NewReader(b)
    io.Copy(&out, r)
    // r不能close
    return out.Bytes()
}

//  @Desc: zlib压缩
//  @param buf 原字符串
//  @return []byte 压缩后的字符串
func ZlibCompress(buf []byte) []byte {
    var in bytes.Buffer
    w := zlib.NewWriter(&in)
    w.Write(buf)
    w.Close()
    return in.Bytes()
}
//  @Desc: 优雅关闭进程
//  @param exitFunc 关闭回周
func CloseGracefully(exitFunc func(sig os.Signal)) {
    stopChan := make(chan os.Signal)
    signal.Notify(stopChan, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGINT)
    select {
    case sig := <-stopChan:
        close(stopChan)
        if exitFunc != nil {
            exitFunc(sig)
        }
    }
}
// @Desc: 按任意键继续
func AnyKeyContinue()  {
    zap.S().Info("按任意键继续...")
	b := make([]byte, 1)
	os.Stdin.Read(b)
}

// @Desc: 判断是不是存在的文件
// @param fn 文件的路径和名字
// @return bool
func IsFileExists(fn string) bool {
	fs, err := os.Stat(fn)
	return err == nil && !fs.IsDir()
}

// @Desc: windows路径，转成linux路径
// @param fn
// @return string
func ToLinuxPath(fn string) string {
	fn = strings.TrimSpace(fn)
	fn = strings.Replace(fn, "\\", "/", -1)
	return fn
}

// @Desc: 格式化网络字节单位
// @param val 要转化的数字
// @return string 转化后的结果，例如  1 B, 233 KB
func FormatNetBytes(val int64) string {
	if val < 1024 {
		return fmt.Sprintf("%d B", val)
	}
	if val < 1048576 {
		return fmt.Sprintf("%.2f KB", float64(val)/1024)
	}
	if val < 1073741824 {
		return fmt.Sprintf("%.2f MB", float64(val)/1048576)
	}
	return fmt.Sprintf("%.2f GB", float64(val)/1073741824)
}

// @Desc: 本机的外网ip
// @return string
func LocalHostNetIp() (string, error) {
	conn, err := net.Dial("udp", "www.baidu.com:80")
	if err != nil {
		return "", err
	}
	defer conn.Close()
	return strings.Split(conn.LocalAddr().String(), ":")[0], nil
}
// @Desc: 转换成string
// @param v
// @return string
func ToString(v interface{}) string {
	switch t := v.(type) {
	case string:
		return t
	case int:
		return strconv.FormatInt(int64(t), 10)
	case int32:
		return strconv.FormatInt(int64(t), 10)
	case int64:
		return strconv.FormatInt(t, 10)
	case uint:
		return strconv.FormatUint(uint64(t), 10)
	case uint32:
		return strconv.FormatUint(uint64(t), 10)
	case uint64:
		return strconv.FormatUint(t, 10)
	}
	zap.S().Debugf("类型:%T 没有在switch中", v)
	return fmt.Sprintf("%v", v)
}

// @Desc: 转换成int64
// @param v
// @return int64
func ToInt64(v string) int64 {
	rlt, _ := strconv.ParseInt(v, 10, 64)
	return rlt
}

// @Desc: 转换成uint64
// @param v
// @return uint64
func ToUInt64(v string) uint64 {
	rlt, _ := strconv.ParseUint(v, 10, 64)
	return rlt
}

// @Desc: 转成uint32
// @param v
// @return uint32
func ToUInt32(v string) uint32 {
	rlt, _ := strconv.ParseUint(v, 10, 32)
	return uint32(rlt)
}

// @Desc: 以当前时间来计算文件名
// @param suffix 文件后缀
// @return string 最终文件名,如: 20220412-17.14.51.csv
func CurTime2FileName(suffix string) string {
	fileName := time.Now().Format("20060102-15.04.05")
	return fmt.Sprintf("%s.%s", fileName, suffix)
}

// @Desc: 随机字符串
// @param n 字符串长度
// @return string
func RandomString(n int) string {
	var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	b := make([]rune, n)
	for i := range b {
		b[i] = letter[rand.Intn(len(letter))]
	}
	return string(b)
}